using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Windows.Threading;
using Microsoft.Practices.Prism.Commands;

public static class DelegateCommandExtensions
{
	/// <summary>
	/// Makes DelegateCommnand listen on PropertyChanged events of some object,
	/// so that DelegateCommnand can update its IsEnabled property.
	/// </summary>
	public static DelegateCommand ListenOn<ObservedType, PropertyType>
		(this DelegateCommand delegateCommand, 
		ObservedType observedObject, 
		Expression<Func<ObservedType, PropertyType>> propertyExpression,
		Dispatcher dispatcher)
		where ObservedType : INotifyPropertyChanged
	{
		//string propertyName = observedObject.GetPropertyName(propertyExpression);
		string propertyName = NotifyPropertyChangedBaseExtensions.GetPropertyName(propertyExpression);

		observedObject.PropertyChanged += (sender, e) =>
        {
        	if (e.PropertyName == propertyName)
        	{
				if (dispatcher != null)
				{
					ThreadTools.RunInDispatcher(dispatcher, delegateCommand.RaiseCanExecuteChanged);
				}
				else
				{
					delegateCommand.RaiseCanExecuteChanged();
				}
        	}
        };

		return delegateCommand; //chain calling
	}

	/// <summary>
	/// Makes DelegateCommnand listen on PropertyChanged events of some object,
	/// so that DelegateCommnand can update its IsEnabled property.
	/// </summary>
	public static DelegateCommand<T> ListenOn<T, ObservedType, PropertyType>
		(this DelegateCommand<T> delegateCommand, 
		ObservedType observedObject, 
		Expression<Func<ObservedType, PropertyType>> propertyExpression,
		Dispatcher dispatcher)
		where ObservedType : INotifyPropertyChanged where T : class
	{
		//string propertyName = observedObject.GetPropertyName(propertyExpression);
		string propertyName = NotifyPropertyChangedBaseExtensions.GetPropertyName(propertyExpression);

		observedObject.PropertyChanged += (object sender, PropertyChangedEventArgs e) =>
        {
        	if (e.PropertyName == propertyName)
        	{
				if (dispatcher != null)
				{
					ThreadTools.RunInDispatcher(dispatcher, delegateCommand.RaiseCanExecuteChanged);
				}
				else
				{
					delegateCommand.RaiseCanExecuteChanged();
				}
        	}
        };

		return delegateCommand; //chain calling
	}
}
